package com.example.module_lzq_haibathree.utils

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import androidx.annotation.IntDef
import com.example.module_lzq_haibathree.R

import java.text.DecimalFormat

/**
 * =====================================================
 * 作    者: Xiuz
 * 创建日期: 2020/7/30 16:59
 * 描    述:
 * =====================================================
 */
class RulerView @JvmOverloads constructor(
    context: Context?,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) :
    View(context, attrs, defStyleAttr) {
    /**
     * 尺子刻度画笔
     */
    private var mRulerCalibrationPaint: Paint? = null

    /**
     * 尺子文字画笔
     */
    private var mRulerTextPaint: Paint? = null

    /**
     * 单位画笔
     */
    private var mUnitTextPaint: Paint? = null

    /**
     * 长刻度长
     */
    private val longCalibrationLength: Float

    /**
     * 滑块宽
     */
    private val sliderWidth: Float

    /**
     * 滑块高
     */
    private val sliderheight: Float

    /**
     * 每个大刻度分成多少小刻度
     */
    private var portion = 10

    /**
     * 默认单位：厘米
     */
    @UnitType
    private var unit: Int = COMPLEX_UNIT_CM

    /**
     * 存放测量出文字的信息
     */
    private val mTextBounds: Rect

    /**
     * 一个单位长度px
     */
    private var oneUnitLength: Float

    /**
     * 滑块画笔
     */
    private var mSliderPaint: Paint? = null

    /**
     * 滑块文字画笔
     */
    private var mSliderTextPaint: Paint? = null

    /**
     * x轴最小值
     */
    private var minX = 0f

    /**
     * x轴最大值
     */
    private var maxX = 0f

    /**
     * y轴最小值
     */
    private var minY = 0f

    /**
     * y轴最大值
     */
    private var maxY = 0f

    /**
     * 当前x轴的值
     */
    private var currentXValue = 0f

    /**
     * 当前y轴的值
     */
    private var currentYValue = 0f

    /**
     * 控制x指针位置,根据当前x轴的值{@param currentXValue}
     */
    private var xValue = 0f

    /**
     * 控制y指针位置,根据当前y轴的值{@param currentYValue}
     */
    private var yvalue = 0f

    /**
     * 控制x滑块的位置
     */
    private val sliderHorizontalRectF: RectF

    /**
     * 控制y滑块的位置
     */
    private val sliderVerticalRectF: RectF
    private val mDecimalFormat: DecimalFormat
    private var mStrUnit: String

    @kotlin.annotation.Retention(AnnotationRetention.SOURCE)
    internal annotation class TouchState {
        companion object {
            var TOUCH_HORIZONTAL = 1
            var TOUCH_VERTICAL = 2
            var TOUCH_IDLE = 0
        }
    }

    @TouchState
    private var touchState = TouchState.TOUCH_IDLE

    @IntDef(COMPLEX_UNIT_IN, COMPLEX_UNIT_CM)
    @kotlin.annotation.Retention(AnnotationRetention.SOURCE)
    annotation class UnitType

    private fun initRulerCalibrationPaint() {
        mRulerCalibrationPaint = Paint().apply {
            isAntiAlias = true
            strokeCap = Paint.Cap.SQUARE
            style = Paint.Style.FILL
            color = Color.BLACK
            strokeWidth = dp2px(1f)
        }
    }

    private fun initRulerTextPaint() {
        mRulerTextPaint = Paint().apply {
            isAntiAlias = true
            strokeCap = Paint.Cap.SQUARE
            style = Paint.Style.FILL
            color = -0xcfcecd
            textSize = dp2px(12f)
        }
    }

    private fun initUnitTextPaint() {
        mUnitTextPaint = Paint().apply {
            isAntiAlias = true
            strokeCap = Paint.Cap.SQUARE
            style = Paint.Style.FILL
            color = resources.getColor(R.color.colorPrimary)
            textSize = dp2px(20f)
        }
    }

    private fun initSliderPaint() {
        mSliderPaint = Paint().apply {
            isAntiAlias = true
            strokeCap = Paint.Cap.SQUARE
            style = Paint.Style.FILL_AND_STROKE
            color = resources.getColor(R.color.colorPrimary)
            strokeWidth = dp2px(1f)
        }
    }

    private fun initSliderTextPaint() {
        mSliderTextPaint = Paint().apply {
            isAntiAlias = true
            strokeCap = Paint.Cap.SQUARE
            style = Paint.Style.FILL
            color = -0xcfcecd
            textSize = dp2px(18f)
        }
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        minX = paddingStart + sliderWidth / 2
        maxX = width - paddingEnd - sliderWidth / 2
        minY = paddingTop + sliderWidth / 2
        maxY = height - paddingBottom - sliderWidth / 2
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        //画单位
        drawUnitText(canvas)

        //画水平方向尺子
        drawHorizontalRuler(canvas, oneUnitLength)

        //画垂直方向尺子
        drawVerticalRuler(canvas, oneUnitLength)

        //画水平方向滑块
        drawHorizontalSlider(canvas)

        //画垂直方向滑块
        drawVerticalSlider(canvas)
    }

    private fun drawVerticalSlider(canvas: Canvas) {
        yvalue = minY + currentYValue * oneUnitLength
        val startX = width - paddingEnd - dp2px(2f)
        canvas.drawLine(startX, yvalue, paddingStart.toFloat(), yvalue, mSliderPaint!!)
        val left = paddingStart - sliderheight
        val top = yvalue - sliderWidth / 2
        val right = paddingStart + sliderheight
        val bottom = top + sliderWidth
        sliderVerticalRectF[left, top, right] = bottom
        canvas.drawArc(sliderVerticalRectF, 270f, 180f, true, mSliderPaint!!)
        val value = mDecimalFormat.format(currentYValue.toDouble())
        mSliderTextPaint!!.getTextBounds(value, 0, value.length, mTextBounds)
        canvas.save()
        canvas.rotate(90f)
        canvas.drawText(
            value, yvalue - mTextBounds.width() / 2f,
            paddingStart - mTextBounds.height() / 2f, mSliderTextPaint!!
        )
        canvas.restore()
    }

    private fun drawHorizontalSlider(canvas: Canvas) {
        xValue = maxX - currentXValue * oneUnitLength
        val stopY = height - paddingBottom.toFloat()
        canvas.drawLine(xValue, paddingTop.toFloat(), xValue, stopY, mSliderPaint!!)
        val left = xValue - sliderWidth / 2
        val top = stopY - sliderheight
        val right = left + sliderWidth
        val bottom = top + sliderheight * 2
        sliderHorizontalRectF[left, top, right] = bottom
        canvas.drawArc(sliderHorizontalRectF, 180f, 180f, true, mSliderPaint!!)
        val value = mDecimalFormat.format(currentXValue.toDouble())
        mSliderTextPaint!!.getTextBounds(value, 0, value.length, mTextBounds)
        canvas.drawText(
            value, xValue - mTextBounds.width() / 2f,
            stopY - mTextBounds.height() / 2f, mSliderTextPaint!!
        )
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                val x = event.x
                val y = event.y
                touchState = if (sliderHorizontalRectF.contains(
                        x,
                        y
                    ) || x >= sliderHorizontalRectF.left && x <= sliderHorizontalRectF.right
                ) {
                    TouchState.TOUCH_HORIZONTAL
                } else if (sliderVerticalRectF.contains(
                        x,
                        y
                    ) || y >= sliderVerticalRectF.top && y <= sliderVerticalRectF.bottom
                ) {
                    TouchState.TOUCH_VERTICAL
                } else {
                    TouchState.TOUCH_IDLE
                }
            }
            MotionEvent.ACTION_MOVE -> {
                if (touchState != TouchState.TOUCH_IDLE) {
                    val x1 = event.x
                    val y1 = event.y
                    if (touchState == TouchState.TOUCH_HORIZONTAL) {
                        val v = currentXValue + (xValue - x1) / oneUnitLength / portion
                        xValue = maxX - v * oneUnitLength
                        if (xValue in minX..maxX) {
                            currentXValue = v
                        }
                    } else {
                        val v = currentYValue + (y1 - yvalue) / oneUnitLength / portion
                        yvalue = minY + v * oneUnitLength
                        if (yvalue in minY..maxY) {
                            currentYValue = v
                        }
                    }
                    postInvalidate()
                }
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> touchState =
                TouchState.TOUCH_IDLE
            else -> touchState = TouchState.TOUCH_IDLE
        }
        return true
    }

    private fun drawUnitText(canvas: Canvas) {
        mUnitTextPaint!!.getTextBounds(mStrUnit, 0, mStrUnit.length, mTextBounds)
        val x =
            (width - paddingStart - paddingEnd - mTextBounds.width()) / 2f
        val y =
            (height - paddingTop - paddingBottom - mTextBounds.height()) / 2f
        canvas.drawText(mStrUnit, x, y, mUnitTextPaint!!)
    }

    private fun drawVerticalRuler(canvas: Canvas, v: Float) {
        //0刻度startY
        val startY = minY
        //有多少个大刻度
        val section = ((height - startY - paddingBottom) / v).toInt()
        val startX = width - paddingEnd - dp2px(2f)
        canvas.drawLine(
            startX, startY, startX, height - paddingBottom.toFloat(),
            mRulerCalibrationPaint!!
        )
        for (i in 0..(section + 1) * portion) {
            val y = startY + v / portion * i
            if (i % portion == 0) {
                canvas.drawLine(
                    startX, y, startX - longCalibrationLength, y,
                    mRulerCalibrationPaint!!
                )
                val s = (i / portion).toString()
                mRulerTextPaint!!.getTextBounds(s, 0, s.length, mTextBounds)
                canvas.drawText(
                    s, startX - longCalibrationLength * 2,
                    v + y + (mTextBounds.width() + dp2px(1f)) / 2f, mRulerTextPaint!!
                )
            }
            if (i % (portion / 2) == 0) {
                canvas.drawLine(
                    startX, y, startX - longCalibrationLength / 1.5f, y,
                    mRulerCalibrationPaint!!
                )
            } else {
                canvas.drawLine(
                    startX, y, startX - longCalibrationLength / 2.5f, y,
                    mRulerCalibrationPaint!!
                )
            }
        }
    }

    private fun drawHorizontalRuler(canvas: Canvas, v: Float) {
        //0刻度startX
        val startX = maxX
        //有多少个大刻度
        val section = ((startX - paddingStart) / v).toInt()
        canvas.drawLine(
            paddingStart.toFloat(),
            paddingTop.toFloat(),
            startX,
            paddingTop.toFloat(),
            mRulerCalibrationPaint!!
        )
        for (i in 0..(section + 1) * portion) {
            val x = startX - v / portion * i
            if (i % portion == 0) {
                canvas.drawLine(
                    x, paddingTop.toFloat(), x, paddingTop + longCalibrationLength,
                    mRulerCalibrationPaint!!
                )
                val s = (i / portion).toString()
                mRulerTextPaint!!.getTextBounds(s, 0, s.length, mTextBounds)
                canvas.drawText(
                    s, x - (mTextBounds.width() + dp2px(1f)) / 2f,
                    paddingTop + longCalibrationLength * 2, mRulerTextPaint!!
                )
            }
            if (i % (portion / 2) == 0) {
                canvas.drawLine(
                    x, paddingTop.toFloat(), x,
                    paddingTop + longCalibrationLength / 1.5f, mRulerCalibrationPaint!!
                )
            } else {
                canvas.drawLine(
                    x, paddingTop.toFloat(), x,
                    paddingTop + longCalibrationLength / 2.5f, mRulerCalibrationPaint!!
                )
            }
        }
    }

    private fun convert2px(value: Float): Float {
        return applyDimension(unit, value, resources.displayMetrics)
    }

    private fun applyDimension(
        unit: Int,
        value: Float,
        metrics: DisplayMetrics
    ): Float {
        return when (unit) {
            COMPLEX_UNIT_IN -> value * metrics.xdpi
            COMPLEX_UNIT_CM -> value * 10 * metrics.xdpi * (1.0f / 25.4f)
            else -> 0f
        }
    }

    private fun dp2px(value: Float): Float {
        return TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, value,
            resources.displayMetrics
        )
    }

    fun setUnit(@UnitType unit: Int) {
        if (this.unit == unit) {
            return
        }
        if (this.unit == COMPLEX_UNIT_IN) {
            oneUnitLength = oneUnitLength * applyDimension(
                COMPLEX_UNIT_CM, 1f,
                resources.displayMetrics
            ) / applyDimension(
                COMPLEX_UNIT_IN,
                1f,
                resources.displayMetrics
            )
            currentXValue *= 2.54f
            currentYValue *= 2.54f
            mStrUnit = resources.getString(R.string.unit_cm)
            portion = 10
        } else {
            oneUnitLength = oneUnitLength * applyDimension(
                COMPLEX_UNIT_IN, 1f,
                resources.displayMetrics
            ) / applyDimension(
                COMPLEX_UNIT_CM,
                1f,
                resources.displayMetrics
            )
            currentXValue /= 2.54f
            currentYValue /= 2.54f
            mStrUnit = resources.getString(R.string.unit_inch)
            portion = 16
        }
        this.unit = unit
        invalidate()
    }

    fun getUnit(): Int {
        return unit
    }

    fun setOneUnitLength(oneUnitLength: Float) {
        this.oneUnitLength = oneUnitLength
        invalidate()
    }

    companion object {
        private val TAG = RulerView::class.java.simpleName
        const val COMPLEX_UNIT_CM = 3
        const val COMPLEX_UNIT_IN = 4
    }

    init {
        initRulerCalibrationPaint()
        initRulerTextPaint()
        initUnitTextPaint()
        initSliderPaint()
        initSliderTextPaint()
        mTextBounds = Rect()
        longCalibrationLength = dp2px(15f)
        sliderWidth = dp2px(64f)
        sliderheight = dp2px(32f)

        //一个单位对应的像素
        oneUnitLength = convert2px(1f)
        sliderHorizontalRectF = RectF()
        sliderVerticalRectF = RectF()
        mDecimalFormat = DecimalFormat("0.00")
        mStrUnit = getContext().resources.getString(R.string.unit_cm)
    }
}
